
import { Node, resources, AudioClip, assetManager, find, isValid, Scene, director, instantiate, view, ResolutionPolicy, AudioSource, sys, js, game, Game, native, log, error, warn } from "cc";
import { DEBUG } from "cc/env";

class LocalStorage {


    getItem(key: string) {
        return localStorage.getItem(key);
    }

    getLength() {
        return localStorage.length
    }

    setItem(key: string, value: string) {
        localStorage.setItem(key, value);
    }

    clear() {
        localStorage.clear();
    }

    removeItem(key: string) {
        localStorage.removeItem(key);
    }
}



class AudioEngine {
    protected musicMgr: AudioSource = new AudioSource()

    protected effectMap: { [k: number]: AudioSource } = {}
    protected effectID: number = 0;
    protected musicAudioID: number = 0;

    constructor() {
        this.musicAudioID = this.createEffectID();
    }
    getMaxAudioInstance() {
        return AudioSource.maxAudioChannel;
    }

    playMusic(res: AudioClip, isLoop: boolean) {
        this.musicMgr.stop();
        this.musicMgr.clip = res;
        this.musicMgr.loop = isLoop;

        this.musicMgr.pause();

        this.musicMgr.play();
        this.effectMap[this.musicAudioID] = this.musicMgr;
        return this.musicAudioID;
    }


    setFinishCallback(audioId: any, func: Function) {
        let as: AudioSource = this.effectMap[audioId]
        if (as) {
            let time = as.duration;
            setTimeout(() => {
                func();
            }, time * 1000);
        }
    }

    protected createEffectID() {
        return Date.now() + this.effectID++
    }

    pauseMusic() {
        this.musicMgr.pause()
    }

    resumeMusic() {
        this.musicMgr.play()
    }

    stopMusic() {
        this.musicMgr.stop();
    }

    setMusicVolume(count: number) {
        this.musicMgr.volume = count
    }

    isMusicPlaying() {
        return this.musicMgr.playing
    }

    playEffect(res: any, playCount: number, func?: Function): number {
        let isLoop = playCount == 0 ? true : false
        let audioID = this.createEffectID();

        if (isLoop) {
            let as: AudioSource = new AudioSource()
            as.clip = res;
            as.loop = isLoop;
            this.effectMap[audioID] = as;
            as.play();
        } else {
            this.musicMgr.playOneShot(res)
        }
        if (func) {
            this.setFinishCallback(audioID, func)
        }
        return audioID
    }

    pauseEffect(audioId: number) {
        // audioEngine.pauseEffect(audioId);
        let as: AudioSource = this.effectMap[audioId]
        if (as) {
            as.pause();
        }
    }



    resumeEffect(audioId: number) {
        // audioEngine.resumeEffect(audioId);
        let as: AudioSource = this.effectMap[audioId]
        if (as) {
            as.play();
        }
    }

    setEffectsVolume(count: number) {
        // audioEngine.setEffectsVolume(count);
        this.musicMgr.volume = count;
    }

    stopEffect(audioId: number) {
        // audioEngine.stopEffect(audioId);
        let as: AudioSource = this.effectMap[audioId]
        if (as) {
            as.stop();
            this.effectMap[audioId] = null;
        }
    }


    uncacheAll() {
        // audioEngine.uncacheAll()
    }
}




export class engine {


    static audioEngine: AudioEngine = new AudioEngine()

    static localStorage: LocalStorage = new LocalStorage()

    static getWritablePath(): string {
        return native.fileUtils.getWritablePath()
    }

    static writeStringToFile(data: any, filePath: string): void {
        native.fileUtils.writeStringToFile(data, filePath)
    }

    static isFileExist(filePath: string): boolean {
        return native.fileUtils.isFileExist(filePath)
    }
    static getStringFromFile(filePath: string): string {
        return native.fileUtils.getStringFromFile(filePath)
    }

    static isDebug() {
        return DEBUG
    }

    static log(...data: any) {
        log(data)
    }

    static error(...data: any) {

        error(data)
    }

    static warn(...data: any) {
        warn(data)
    }

    static addChild(node: Node, parent: Node) {
        parent.addChild(node)
    }
    /**
     * 
     * @param className 
     * @param methodName 
     * @param parameters 
     * @param methodSignature 
     */
    static callStaticMethod(className: string, methodName: string, parameters: any, methodSignature = "(Ljava/lang/String;)V") {
        // console.log(" JsNativeBridge callStaticMethod ", sys.isNative)
        // if (!sys.isNative) {
        //     return -1;
        // }
        console.log(" JsNativeBridge callStaticMethod ", methodName, parameters)
        if (sys.os == sys.OS.IOS) {
            let result = native.reflection.callStaticMethod(className, methodName, parameters);
            if (result) {
                console.log("callStaticMethod ios  ", result);
            }
        } else {
            console.log(" JsNativeBridge callStaticMethod adroid ")
            let result = native.reflection.callStaticMethod(className, methodName, methodSignature, parameters)
            console.log("callStaticMethod result  ", result);
            if (result) {

                return result;
            }
        }
    }

    static hasNative(): boolean {
        return native && native.reflection != undefined;
    }

    static createCanvas() {
        let canvas = document.createElement('canvas')
        console.log(' canvas ', canvas)
        return canvas;
    }



    static getChildByIndex(node: Node, index: number) {
        return node.children[index]
    }

    static findChild(name: string, node: Node) {
        let temp = find(name, node);
        if (temp) {
            return temp;
        } else {
            let count = node.children.length;
            for (let index = 0; index < count; index++) {
                const element = node.children[index];
                temp = this.findChild(name, element);
                if (temp) {
                    return temp;
                }
            }
            return null;
        }
    }

    static isValid(node: Node) {
        return isValid(node)
    }


    static getDefaultBundle() {
        return resources
    }

    static loadRemote(url: string, callback: Function) {
        assetManager.loadRemote(url, callback)
    }

    static loadBundle(url: string, callback: Function) {
        assetManager.loadBundle(url, callback)
    }


    static getBundle(url: string) {
        return assetManager.getBundle(url)
    }

    static loadScene(sceneName: string, func: Function) {
        director.loadScene(sceneName, (error: any, scene: Scene) => {
            func(error, scene)
        })
    }

    static runScene(scene: Scene) {
        director.runScene(scene)
    }

    static instantiate(res: any) {
        return instantiate(res)
    }


    static getComponent(node: Node, className: any): any {
        return node.getComponent(className)
    }

    static getChildByName(node: Node, name: string): any {
        return node.getChildByName(name)
    }

    static getFrameSize() {
        return view.getFrameSize();
    }

    static getVisibleSize() {
        return view.getVisibleSize();
    }

    static getDesignSize() {
        return view.getDesignResolutionSize()
    }

    static getDesignResolutionSize() {
        return view.getDesignResolutionSize()
    }

    static frameAspectRatio() {
        let fs = this.getFrameSize()
        return fs.width / fs.height;
    }

    static designAspectRatio() {
        let ds = this.getDesignSize();
        return ds.width / ds.height;
    }

    static resizeUI(config?: any) {

        let dr = this.getDesignSize();
        console.log(' dr ', dr)
        var s = this.getFrameSize()
        console.log(' s ', s)
        var rw = s.width;
        var rh = s.height;
        var finalW = rw;
        var finalH = rh;

        if (this.frameAspectRatio > this.designAspectRatio) {
            //!#zh: 是否优先将设计分辨率高度撑满视图高度。 */
            //cvs.fitHeight = true;

            //如果更长，则用定高
            finalH = dr.height;
            finalW = finalH * rw / rh;
        }
        else {
            /*!#zh: 是否优先将设计分辨率宽度撑满视图宽度。 */
            //cvs.fitWidth = true;
            //如果更短，则用定宽
            finalW = dr.width;
            finalH = rh / rw * finalW;
        }

        view.setDesignResolutionSize(finalW, finalH, ResolutionPolicy.UNKNOWN);
        // let cvs: Canvas = Canvas
        // cvs.node.width = finalW;
        // cvs.node.height = finalH;
    }

    static getClassByName(name: string) {
        return js.getClassByName(name)
    }

    static isPaused() {
        return game.isPaused()
    }

    static eventShow() {
        game.emit(Game.EVENT_SHOW)
    }

    static eventHide() {
        game.emit(Game.EVENT_HIDE)
    }

}



